package simulation;

import java.util.ArrayList;

import edu.cornell.lassp.houle.RngPack.Ranlux;
import evaluation.EvaluationMetric;

import randomwalk.QuizSetVerification;

import musictrackrecommendation.DatabaseDataset;
import musictrackrecommendation.ExperimentParameters;

/**
 * @author  user
 */
public class RandomWalkWithRestartsSimulation {
	private int userId;
	private double [] tracksVisit;
	/**
	 * @uml.property  name="startDistribution"
	 * @uml.associationEnd  
	 */
	private UserStepDistribution startDistribution;
	
	public RandomWalkWithRestartsSimulation(int userId) {
		this.userId = userId;
		DatabaseDataset dataset = ExperimentParameters.getInstance().getDatasetDatabase();
		tracksVisit = new double [dataset.getTracksMaximalId()+1];
		startDistribution = new UserStepDistribution(userId);
	}
	
	private void startSimulation(int stepsCount) {
		double restartProbability = 
			ExperimentParameters.getInstance().getRestartProbability();
		
		Ranlux random = new Ranlux(System.currentTimeMillis());
		int currentStep = 0;
		int walkDepth = 0;
		ItemStepDistribution distr = startDistribution;
		
		while (currentStep < stepsCount) {
			if(random.raw() < restartProbability && walkDepth > 1) {
				//restart
				distr = startDistribution;
				walkDepth = 0;
			}
			int nextItemPosition = distr.nextItem();
			int nextItemId = distr.getCdf().getItemIds().get(nextItemPosition);
			
			if (nextItemPosition < distr.getCdf().getFirstTrackId()) {
				//it`s userId
					distr = new UserStepDistribution(nextItemId);
			}
			else {
				//it`s trackId
				distr = new TrackStepDistribution(nextItemId);
				tracksVisit [nextItemId]+=1.0;
			}
			currentStep++;
			walkDepth++;
		}
	}
	
	public void randomWalkWithRestarts(int stepsCount) {
		startSimulation(stepsCount);
		
		EvaluationMetric[] metrics = 
			ExperimentParameters.getInstance().getMetrics();
		QuizSetVerification verification = 
			new QuizSetVerification(userId);

		for (int i = 0; i < tracksVisit.length; i++) {
			if(tracksVisit[i] > 0.0) {
				tracksVisit[i] += ((double) i) / 10000000.0;
			}
		}
		
		ArrayList<Integer> topTracks = verification
				.prepareTopTracks(tracksVisit, tracksVisit.length);
		
		for(EvaluationMetric metric : metrics) {
			metric.addRecommendation(userId, topTracks, verification);
		}
		
	}
}
